import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
import 'package:flutter_widget/src/widget/image/web_cache_Image.dart';

typedef AsyncImageWidgetBuilder<T> = Widget Function(
  BuildContext context,
  AsyncSnapshot<T> snapshot,
  String? url,
);

typedef AsyncImageFileWidgetBuilder<T> = Widget Function(
  BuildContext context,
  AsyncSnapshot<T> snapshot,
  File? file,
);

typedef AsyncImageAssetWidgetBuilder<T> = Widget Function(
    BuildContext context,
    AsyncSnapshot<T> snapshot,
    AssetImage? asset,
);

typedef AsyncImageMemoryWidgetBuilder<T> = Widget Function(
  BuildContext context,
  AsyncSnapshot<T> snapshot,
  Uint8List? bytes,
);

enum AspectRatioImageType {
  NETWORK,
  FILE,
  ASSET,
  MEMORY,
}

///可用来获取图片宽高，设置宽高比的Image
// eg:
// AspectRatioImage.memory(imageBytes, memoryBuilder: (context, snapshot, bytes){
//   var imageRatio = snapshot.data.width / snapshot.data.height;
//   return 根据宽高比处理的图片widget;
// },);
// ignore: must_be_immutable
class AspectRatioImage extends StatelessWidget {
  String? url;
  File? file;
  Uint8List? bytes;
  ImageProvider provider;
  AspectRatioImageType type;
  AsyncImageWidgetBuilder<ui.Image>? builder;
  AsyncImageFileWidgetBuilder<ui.Image>? fileBuilder;
  AsyncImageAssetWidgetBuilder<ui.Image>? assetBuilder;
  AsyncImageMemoryWidgetBuilder<ui.Image>? memoryBuilder;
  Widget? placeHolder = Container();

  /*网络图片使用
  * bulder，实现该方法，获取到图片后会回调，可以拿到图片快照*/
  AspectRatioImage.network(
    this.url, {
    Key? key,
    required this.builder,
    this.placeHolder,
  })  : provider = WebImageProvider(url),
        type = AspectRatioImageType.NETWORK,
        super(key: key);

  /*本地图片使用*/
  AspectRatioImage.file(
    this.file, {
    Key? key,
    required this.fileBuilder,
  })  : provider = FileImage(file!),
        type = AspectRatioImageType.FILE,
        super(key: key);

  AspectRatioImage.asset(
    name, {
    Key? key,
    required this.assetBuilder,
  })  : provider = AssetImage(name),
        type = AspectRatioImageType.ASSET,
        url = name,
        super(key: key);

  AspectRatioImage.memory(
    this.bytes, {
    Key? key,
    required this.memoryBuilder,
  })  : provider = MemoryImage(bytes!),
        type = AspectRatioImageType.MEMORY,
        super(key: key);

  @override
  Widget build(BuildContext context) {
    final ImageConfiguration config = createLocalImageConfiguration(context);
    final Completer<ui.Image> completer = Completer<ui.Image>();
    final ImageStream stream = provider.resolve(config);
    late ImageStreamListener listener;
    listener = ImageStreamListener(
      (ImageInfo image, bool sync) {
        completer.complete(image.image);
        stream.removeListener(listener);
      },
      onError: (dynamic exception, StackTrace? stackTrace) {
        completer.complete();
        stream.removeListener(listener);
        FlutterError.reportError(FlutterErrorDetails(
          context: ErrorDescription('image failed to precache'),
          library: 'image resource service',
          exception: exception,
          stack: stackTrace,
          silent: true,
        ));
      },
    );
    stream.addListener(listener);

    return FutureBuilder(
        future: completer.future,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          if (snapshot.hasData) {
            if (type == AspectRatioImageType.FILE) {
              return fileBuilder!(context, snapshot, file);
            } else if (type == AspectRatioImageType.ASSET) {
              return assetBuilder!(context, snapshot, provider as AssetImage);
            } else if (type == AspectRatioImageType.MEMORY) {
              return memoryBuilder!(context, snapshot, bytes);
            } else {
              return builder!(context, snapshot, url);
            }
          } else {
            return placeHolder ?? Container();
          }
        });
  }
}
